﻿using System;
using System.Linq;
using StreetPacMan.Server.Facade;
using StreetPacMan.Server.Rules.PlayerLocationChangeRules;

namespace StreetPacMan.Server.Rules
{
    public class PacManGhostCollisionRule : IHandlePlayerLocationChangedRule
    {
        private readonly IPacManGhostCollisionRule[] _CollisionRules;

        public PacManGhostCollisionRule()
        {
            _CollisionRules = new IPacManGhostCollisionRule[]
                                  {
                                      new EatTheVaulnrablePlayerRule(), 
                                      new GameOverIfGhostAteLastPacManRule(),
                                      new AddScoreIfPacManAteGhostRule()
                                  };
        }

        public void Handle(PacManDataContext dataContext, ServerPollParameters serverPollParameters, ref bool shouldContinueHandling)
        {
            var updateEntity = dataContext.Players.Where(x => x.Id == serverPollParameters.EntityId).Single();
            
            var activePlayersIn10MeterRadius = dataContext
                .Players
                .Where(x => x.GameId == updateEntity.GameId)
                .Where(x => x.State == (int)PlayerState.JoinedActivePlaying)
                .ToArray()
                .Where(x => TwoGeos.GetDistance(updateEntity.LastGeoLat, updateEntity.LastGeoLon,
                                                              x.LastGeoLat, x.LastGeoLon)< GameDistances.SameLocationMaxRange);

            Player pacman, ghost;
            switch (updateEntity.RoleEnum)
            {
                case PlayerRole.PacMan:
                    pacman = updateEntity;
                    ghost = activePlayersIn10MeterRadius.Where(x => x.Role == (int)PlayerRole.Ghost).FirstOrDefault();
                    break;
                case PlayerRole.Ghost:
                    ghost = updateEntity;
                    pacman = activePlayersIn10MeterRadius.Where(x => x.Role == (int)PlayerRole.PacMan).FirstOrDefault();
                    break;
                case PlayerRole.Observer:
                    return ;

                default:
                    throw new ArgumentOutOfRangeException();
            }

            if (pacman == null || ghost==null)
            {
                return;
            }

            foreach (var applesEatingRule in _CollisionRules)
            {
                applesEatingRule.DoSideEffects(pacman, ghost, dataContext);
            }

            dataContext.SubmitChanges();
        }
    }
}